﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Filters;
using System.Net;
using System.Text;
using Autofac.Integration.WebApi;
using Pay.Core;
using Autofac;
using Pay.TO;
using System.Web.Http.Controllers;
using System.Web.Http;
using System.Web.Http.Dispatcher;

namespace Pay.Token {
    /// <summary>
    /// api全局自定义异常处理
    /// </summary>
    public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute {
        public override void OnException(HttpActionExecutedContext actionExecutedContext) {
            int errorCode = 0;
            string message = LogError(actionExecutedContext, out errorCode);
            actionExecutedContext.Response = GetResponseMessage(errorCode, message);
        }

        private HttpResponseMessage GetResponseMessage(int errorCode, string message) {
            return new HttpResponseMessage() {
                Content = new StringContent(ResultToJson.Json<object>(errorCode, message, null).ToJson(), Encoding.UTF8, "application/json")
            };
        }

        private string LogError(HttpActionExecutedContext ex, out int errorCode) {
            string message = string.Empty;
            errorCode = 0;
            var request = ex.Request;
            var requestScope = request.GetDependencyScope();
            var requestLifetimeScope = requestScope.GetRequestLifetimeScope();
            var logHelper = requestLifetimeScope.ResolveNamed<ILogHelper>("ui_error");
            if (ex.Exception is ServerErrorException) {
                message = ex.Exception.Message;
                if (message.Contains(":")) {
                    var arr = message.Split(':');
                    message = arr[0];
                    errorCode = int.Parse(arr[1]);
                }
            } else {
                if (ex.Exception is NotImplementedException)
                    message = "请求的资源不在服务器上";
                else if (ex.Exception is TimeoutException)
                    message = "请求的资源超时";
                else
                    message = "网络异常，请稍后再试";
                errorCode = 500;
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("Message:{0}\r\n", ex.Exception.Message);
                sb.AppendFormat("StackTrace:{0}\r\n", ex.Exception.StackTrace);
                sb.AppendFormat("Url:{0}\r\n", request.RequestUri);
                sb.AppendFormat("Method:{0}\r\n", request.Method);
                sb.AppendFormat("ContentType:{0}\r\n", request.Content.Headers.ContentType);
                sb.AppendFormat("RequestOther:{0}\r\n", ex.ActionContext.ActionArguments.Values.ToJson());
                if (request.Headers.Authorization != null)
                    sb.AppendFormat("token:{0}\r\n", request.Headers.Authorization.Parameter);

                logHelper.Error(sb.ToString());
                message = string.Empty;
            }
            return message;
        }

        private string GetMessage(HttpStatusCode httpStatusCode) {
            string message = string.Empty;
            switch (httpStatusCode) {
                case HttpStatusCode.MethodNotAllowed:
                    message = "指示请求的资源上不允许请求方法";
                    break;
                case HttpStatusCode.NotFound:
                    message = "指示请求的资源不在服务器上";
                    break;
                case HttpStatusCode.Unauthorized:
                    message = "指示请求的资源要求身份验证";
                    break;
                case HttpStatusCode.Forbidden:
                    message = "指示服务器拒绝满足请求";
                    break;
                case HttpStatusCode.NotAcceptable:
                    message = "指示客户端已用 Accept 头指示将不接受资源的任何可用表示形式";
                    break;
                case HttpStatusCode.PreconditionFailed:
                    message = "指示为此请求设置的条件失败，且无法执行此请求。条件是用条件请求标头（如 If-Match、If-None-Match 或 If-Unmodified-Since）设置的";
                    break;
                case HttpStatusCode.NotImplemented:
                    message = "指示服务器不支持请求的函数";
                    break;
                case HttpStatusCode.BadGateway:
                    message = "指示中间代理服务器从另一代理或原始服务器接收到错误响应";
                    break;
                case HttpStatusCode.BadRequest:
                    message = "指示服务器未能识别请求";
                    break;
                default:
                    message = "网络异常，请稍后再试";
                    break;
            }
            return message;
        }
    }

    public class NotFoundActionSelector : ApiControllerActionSelector {
        public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) {
            HttpActionDescriptor decriptor = null;
            try {
                decriptor = base.SelectAction(controllerContext);
            } catch (HttpResponseException ex) {
                var code = ex.Response.StatusCode;
                if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed)
                    throw;
                var routeData = controllerContext.RouteData;
                routeData.Values["action"] = "Handle404";
                IHttpController httpController = new ErrorController();
                controllerContext.Controller = httpController;
                controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
                decriptor = base.SelectAction(controllerContext);
            }
            return decriptor;
        }
    }

    public class NotFoundControllerSelector : DefaultHttpControllerSelector {
        public NotFoundControllerSelector(HttpConfiguration configuration)
            : base(configuration) {
        }

        public override HttpControllerDescriptor SelectController(HttpRequestMessage request) {
            HttpControllerDescriptor decriptor = null;
            try {
                decriptor = base.SelectController(request);
            } catch (HttpResponseException ex) {
                var code = ex.Response.StatusCode;
                if (code != HttpStatusCode.NotFound)
                    throw;
                var routeValues = request.GetRouteData().Values;
                routeValues["controller"] = "Error";
                routeValues["action"] = "Handle404";
                decriptor = base.SelectController(request);
            }
            return decriptor;
        }
    }

    public class ErrorController : ApiController {
        [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH")]
        public ResultMessage<object> Handle404() {
            return ResultToJson.Json<object>((int)HttpStatusCode.NotFound, "请求不存在", null);
        }
    }
}